﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace KaartenLib
{
    public class Speler
    {
        private string naam = null;
        private int beginPunten = -1;
        private int winst = 0;
        private int[] inzet;
        private double[] factor = {2, 3, 2, 1.5 };
        private object[] vereiste;

        /// <summary>
        /// Geeft het aantal punten terug dat men momenteel bezit.
        /// </summary>
        public int Punten {
            get {
                return (this.BeginPunten + winst);
            }
        }

        /// <summary>
        /// naam setten en getten.
        /// </summary>
        public string Naam {
            get {
                if (naam == null) {
                    throw new ArgumentException("Naam nog niet geset.");
                }
                return naam;
            }
            set {
                if (value == null || value.Equals(""))
                {
                    throw new ArgumentException("Naam is verplicht.");
                }
                naam = value;
            }
        }

        /// <summary>
        /// beginPunten setten en getten.
        /// </summary>
        public int BeginPunten {
            get {
                if (beginPunten < 0)
                {
                    throw new ArgumentException("beginpunten nog niet geset.");
                }
                return beginPunten;
            }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("Beginpunten moeten ingevuld worden.");
                }
                beginPunten = value;
            }
        }

        /// <summary>
        /// Punten inzetten
        /// </summary>
        /// <param name="Punten">Kan</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Wordt gegooid wanneer het verlies groter is dan de nog beschikbare punten.
        /// </exception>
        private void Inzet(int Punten) {
            if ((this.BeginPunten + this.winst + Punten) < 0)
            {
                throw new ArgumentOutOfRangeException("Meer verliezen dan dat men bezit is onmogelijk.");
            }
            this.winst += Punten;
        }

        /// <summary>
        /// Maak een speler object.
        /// </summary>
        public Speler()
        {
            vereiste = new object[factor.Length];
            inzet = new int[factor.Length];
        }

        /// <summary>
        /// Een speler object maken.
        /// </summary>
        /// <param name="naam">een String met de naam</param>
        /// <param name="beginPunten">de beginpunten</param>
        public Speler(string naam, int beginPunten) : this(){
            this.Naam = naam;
            this.BeginPunten = beginPunten;
            
        }

        /// <summary>
        /// HashCode
        /// </summary>
        /// <returns>
        /// De hashcode van de naam.
        /// </returns>
        public override int GetHashCode()
        {
            return this.Naam.GetHashCode();
        }

        /// <summary>
        /// Gaat kijken of het gelijk is.
        /// </summary>
        /// <param name="obj">object om mee te vergelijken</param>
        /// <returns>
        ///     gelijk indien obj een instancie is van de Speler klasse en de hashcodes gelijk zijn.
        /// </returns>
        public override bool Equals(object obj)
        {
            return (obj is Speler) && (obj.GetHashCode() == this.GetHashCode());
        }

        /// <summary>
        /// Geeft een String terug met alle belangrijke gegevens.
        /// </summary>
        /// <returns>
        ///     naam: BeginPunten heeft nu nog Punten
        /// </returns>
        public override string ToString()
        {
            return this.Naam + ": " + this.BeginPunten + " heeft nu nog " + this.Punten;
        }

        public void AantalPunten21(int aantal) {
            inzet[0] += aantal;
        }

        public void WinstAantalPunten21() {
            this.Inzet(Math.Abs((int) (inzet[0] * factor[0])));
            inzet[0] = 0;
        }

        public object Troef {
            set {
                if (value != null && value is Kaart)
                {
                    vereiste[1] = value;
                }
            }
            get {
                return vereiste[1];
            }
        }

        public void AantalPuntenTroef(int aantal) { 
            inzet[1] += aantal;
        }

        public void WinstAantalPuntenTroef()
        {
            this.Inzet((int)(inzet[1] * factor[1]));
            inzet[1] = 0;
            WinstAantalPunten21();
        }

        public object ReeksType {
            set {
                if (value != null && value is KaartSoort) {
                    vereiste[2] = value;
                }
            }
            get {
                return vereiste[2];
            }
        }

        public void AantalPuntenZelfdeType(int aantal)
        {
            inzet[2] += aantal;
        }

        public void WinstAantalPuntenZelfdeType()
        {
            this.Inzet((int)(inzet[2] * factor[2]));
            inzet[2] = 0;
            WinstAantalPunten21();
        }

        public void AantalPuntenOpeenvolgend(int aantal)
        {
            inzet[3] += aantal;
        }

        public void WinstAantalPuntenOpeenvolgend()
        {
            this.Inzet((int)(inzet[3] * factor[3]));
            inzet[3] = 0;
            WinstAantalPunten21();
        }

        public void Verlies() {
            int punten = 0;
            for (int i = 0; i < factor.Length; i++) {
                punten -= ((int)(factor[i] * inzet[i]));    
            }
            this.Inzet(punten);
        }

        private int this[int nr]
        {
            set {
                int punten = 0;
                for(int i = 0;i<factor.Length;i++){
                    punten += (int) (factor[i] * inzet[i]);
                }
                if ((inzet[nr] + value) >= 0 && (this.Punten - punten) >= (value * factor[nr]))
                {
                    inzet[nr] += value;
                }
            }
            get {
                return inzet[nr];
            }
        }

        public Boolean IsKlaar() {
            return ((inzet[1] > 0 && vereiste[1] != null) || (inzet[1] == 0)) && ((inzet[2] > 0 && vereiste[2] != null) || (inzet[2] == 0));
        }

        /// <summary>
        /// Deze gaat een xml maken van de belangrijkste gegevens
        /// </summary>
        /// <returns>
        ///     een xml met de volgende sturctuur:
        ///         - speler
        ///             - naam
        ///             - startKapitaal
        ///             - eindKapitaal
        /// </returns>
        public XmlElement toXML(ref XmlDocument doc)
        {
            XmlElement speler = doc.CreateElement("speler");
            XmlElement naam = doc.CreateElement("naam");
            naam.InnerText = this.Naam;
            speler.AppendChild(naam);
            XmlElement startKapitaal = doc.CreateElement("startkapitaal");
            startKapitaal.InnerText = this.BeginPunten + "";
            speler.AppendChild(startKapitaal);
            XmlElement eindKapitaal = doc.CreateElement("eindkapitaal");
            eindKapitaal.InnerText = this.Punten + "";
            speler.AppendChild(eindKapitaal);
            return speler;
        }

        public bool IsLogged()
        {
            return this.naam != null && !this.naam.Equals("") && this.beginPunten >= 0;
        }
    }
}
